﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AGisCore.Entity;
using DigitalImage.probabilistic;
using DigitalImage.util;
using OcrTemplate.Utilities;
using DigitalImage.neuronska;

namespace DigitalImage
{
    public partial class FrmColorSegmentation : Form
    {
        private btnCreateSimLib mainForm = null;
        private Bitmap orginalImage = null;

        public FrmColorSegmentation(btnCreateSimLib mainForm)
        {
            InitializeComponent();
            this.mainForm = mainForm;
            Bitmap bmp = mainForm.imageEditorDisplay1.mapa.bmp;
            orginalImage = (Bitmap)mainForm.imageEditorDisplay1.mapa.bmp.Clone();
        }

        private void btnKMeans_Click(object sender, EventArgs e)
        {
            if (mainForm.imageEditorDisplay1.mapa.poligoni.Count > 0)
            {
                byte[, ,] slika = ImageUtil.bitmapToColorMatrix(orginalImage);
                Poligon pol = mainForm.imageEditorDisplay1.mapa.poligoni[0];
                Poligon bb = pol.getBoundingBox();
                int xMin = (int)bb.tacke[0].x;
                int xMax = (int)bb.tacke[1].x;

                int yMin = (int)bb.tacke[0].y;
                int yMax = (int)bb.tacke[2].y;

                Dictionary<Color, int> colorHistogram = new Dictionary<Color, int>();
                for (int y = yMin; y < yMax; y++)
                {
                    for (int x = xMin; x < xMax; x++)
                    {
                        byte cbR = slika[y, x, 0];
                        byte cbG = slika[y, x, 1];
                        byte cbB = slika[y, x, 2];

                        Color cc = Color.FromArgb(cbR, cbG, cbB);
                        if (colorHistogram.ContainsKey(cc))
                        {
                            int n = colorHistogram[cc];
                            n++;
                            colorHistogram[cc] = n;
                        }
                        else
                        {
                            colorHistogram.Add(cc, 1);
                        }
                    }
                }

                KMeans kmeans = new KMeans(); // inicijalizacija
                int brojGrupa = 0;
                // inicijalizovati podatke koje ce K-means da klasterizuje i pokrenuti algoritam
                // postavljanje elemenata koje je potrebno klasterizovati
                foreach (Color key in colorHistogram.Keys)
                {
                    kmeans.elementi.Add(key);
                }
                brojGrupa = int.Parse(tbBrojGrupa.Text);
                // pokretanje K-means algoritma
                kmeans.podeliUGRupe(brojGrupa, 10);

                // iscrtavanje podataka
                for (int i = 0; i < brojGrupa; i++)
                {
                    Cluster grupa = kmeans.grupe[i];
                    Color cc = grupa.centar;
                    foreach (Color c in grupa.elementi)
                    {
                        int cbR = c.R;
                        int cbG = c.G;
                        int cbB = c.B;

                        Tacka ttRB = new Tacka(cbR, cbB, cc);
                        imageEditorDisplay1.mapa.tacke.Add(ttRB);
                        imageEditorDisplay1.selectedIndexer.add(ttRB);

                        Tacka ttRG = new Tacka(cbR + 300, cbG, cc);
                        imageEditorDisplay1.mapa.tacke.Add(ttRG);
                        imageEditorDisplay1.selectedIndexer.add(ttRG);

                        Tacka ttGB = new Tacka(cbG, cbB + 300, cc);
                        imageEditorDisplay1.mapa.tacke.Add(ttGB);
                        imageEditorDisplay1.selectedIndexer.add(ttGB);

                    }
                }

                // -------- primeniti filter na sliku ----------------
                DateTime d1 = DateTime.Now;
                int w = slika.GetLength(1);
                int h = slika.GetLength(0);
                byte[, ,] nslika = new byte[h, w, 3];
                
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        byte cbR = slika[y, x, 0];
                        byte cbG = slika[y, x, 1];
                        byte cbB = slika[y, x, 2];
                        Color cc = Color.FromArgb(255, cbR, cbG, cbB);

                        // za svaki piksel na slici odrediti kojem klasteru pripada
                        // pronalazenje indeksa (rednog broja) klastera kojem pripada piksel
                        int najbliza = 0;
                        for (int i = 1; i < brojGrupa; i++)
                        {
                            Cluster grupa = kmeans.grupe[i];
                            if (grupa.rastojanje(cc) < kmeans.grupe[najbliza].rastojanje(cc))
                            {
                                najbliza = i;
                            }
                        }
                        Cluster najblizaGrupa = kmeans.grupe[najbliza];
                        Color boja = najblizaGrupa.centar;
                        nslika[y, x, 0] = boja.R;
                        nslika[y, x, 1] = boja.G;
                        nslika[y, x, 2] = boja.B;
                    }
                }
                Bitmap into = ImageUtil.colorMatrixToBitmap(nslika);
                mainForm.imageEditorDisplay1.mapa.bmp = into;
                mainForm.imageEditorDisplay1.FitImage();
                mainForm.imageEditorDisplay1.Refresh();

                imageEditorDisplay1.Refresh();
            }
        }

        private void btnBayesKlasifikacija_Click(object sender, EventArgs e)
        {
            if (mainForm.imageEditorDisplay1.mapa.poligoni.Count > 1)
            {
                byte[, ,] slika = ImageUtil.bitmapToColorMatrix(orginalImage);
                List<Color> skupK1 = new List<Color>();
                List<Color> skupK2 = new List<Color>();
                for (int i = 0; i < mainForm.imageEditorDisplay1.mapa.poligoni.Count; i++)
                {
                    Poligon pol0 = mainForm.imageEditorDisplay1.mapa.poligoni[i];
                    Poligon bb0 = pol0.getBoundingBox();
                    int xMin0 = (int)bb0.tacke[0].x;
                    int xMax0 = (int)bb0.tacke[1].x;

                    int yMin0 = (int)bb0.tacke[0].y;
                    int yMax0 = (int)bb0.tacke[2].y;

                    for (int y = yMin0; y < yMax0; y++)
                    {
                        for (int x = xMin0; x < xMax0; x++)
                        {
                            // napuniti skupove K1 i K2 (klasa 1 i klasa 2)
                            // piksel ide u K1 ako je unutar poligona sa parnim indeksom
                            // piksel ide u K2 ako je unutar poligona sa neparnim indeksom
                            byte cbR = slika[y, x, 0];
                            byte cbG = slika[y, x, 1];
                            byte cbB = slika[y, x, 2];

                            Color cc = Color.FromArgb(cbR, cbG, cbB);
                            if ((i % 2) == 0)
                                skupK1.Add(cc);
                            else
                                skupK2.Add(cc);
                        }
                    }
                }

                BayesFilter bayesFilter = new BayesFilter(skupK1, skupK2);
                bayesFilter.obucavanje();

                // -------- primeniti filter na sliku ----------------
                DateTime d1 = DateTime.Now;
                int w = slika.GetLength(1);
                int h = slika.GetLength(0);
                byte[, ,] nslika = new byte[h, w, 3];

                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        // za svaki piksel na slici odrediti verovatnocu da pripada klasi 1
                        // pozvati metodu "pK1akojeRGB"
                        byte cbR = slika[y, x, 0];
                        byte cbG = slika[y, x, 1];
                        byte cbB = slika[y, x, 2];
                        Color cc = Color.FromArgb(255, cbR, cbG, cbB);
                        // racunanje verovatnoce da boja piksela pripada prvoj klasi
                        double pk1rgb = bayesFilter.pK1akojeRGB(cc);
                        // verovatnoca - realna vrednost u intervalu [0,1]
                        // se skalira na celobroju vrednost u intervalu [0, 255]
                        // - crno - ne pripada klasi 1
                        // - belo - pripada klasi 1
                        // - nijansa sive - delimicno pripada klasi 1
                        byte skalirano = (byte)(255 * pk1rgb);

                        // sve tri komponente (R,G,B) se postavljaju istu vrednost
                        // kako bi se dobila grayscale rezultujuca slika
                        nslika[y, x, 0] = skalirano;
                        nslika[y, x, 1] = skalirano;
                        nslika[y, x, 2] = skalirano;
                    }
                }
                Bitmap into = ImageUtil.colorMatrixToBitmap(nslika);
                mainForm.imageEditorDisplay1.mapa.bmp = into;
                mainForm.imageEditorDisplay1.FitImage();
                mainForm.imageEditorDisplay1.Refresh();

                imageEditorDisplay1.Refresh();
            }
        }

        SOMnn som = null;
        private void btnSOM_Click(object sender, EventArgs e)
        {
            if (mainForm.imageEditorDisplay1.mapa.poligoni.Count > 0)
            {
                byte[, ,] slika = ImageUtil.bitmapToColorMatrix(orginalImage);
                Poligon pol = mainForm.imageEditorDisplay1.mapa.poligoni[0];
                Poligon bb = pol.getBoundingBox();
                int xMin = (int)bb.tacke[0].x;
                int xMax = (int)bb.tacke[1].x;

                int yMin = (int)bb.tacke[0].y;
                int yMax = (int)bb.tacke[2].y;

                List<double[]> obSkup = new List<double[]>();
                for (int y = yMin; y < yMax; y++)
                {
                    for (int x = xMin; x < xMax; x++)
                    {
                        byte cbR = slika[y, x, 0];
                        byte cbG = slika[y, x, 1];
                        byte cbB = slika[y, x, 2];

                        double[] vektor = new double[3];
                        vektor[0] = cbR / 255.0;
                        vektor[1] = cbG / 255.0;
                        vektor[2] = cbB / 255.0;
                        obSkup.Add(vektor);
                    }
                }

                int dim = int.Parse(tbSOMDim.Text);
                som = new SOMnn(3, dim, obSkup);
                som.imageEditorDisplay = imageEditorDisplay1;
                som.Obucavanje(0.0001, 5000, cbUbrzano.Checked);

                lblUkupnoVreme.Text = "Ukupno vreme: " + som.UkupnoVreme.ToString(@"mm\:ss\:fff");

                byte[, ,] ss = som.Mapa2Slika();
                byte[, ,] distanceMap = som.DistanceMap();
                Bitmap comp = ImageUtil.MergeTwoImages(ImageUtil.colorMatrixToBitmap(ss), ImageUtil.colorMatrixToBitmap(distanceMap));

                imageEditorDisplay1.mapa.bmp = comp;
                imageEditorDisplay1.FitImage();
                imageEditorDisplay1.Refresh();

                for (int y = 0; y < slika.GetLength(0); y++)
                {
                    for (int x = 0; x < slika.GetLength(1); x++)
                    {
                        byte cbR = slika[y, x, 0];
                        byte cbG = slika[y, x, 1];
                        byte cbB = slika[y, x, 2];

                        double[] vektor = new double[3];
                        vektor[0] = cbR / 255.0;
                        vektor[1] = cbG / 255.0;
                        vektor[2] = cbB / 255.0;

                        double[] pripadnosti = som.Pripadnosti(vektor);
                        byte bojaK1 = (byte)(pripadnosti[0] * 255);
                        byte bojaK2 = (byte)(pripadnosti[1] * 255);

                        slika[y, x, 0] = bojaK1;
                        slika[y, x, 1] = bojaK1;
                        slika[y, x, 2] = bojaK1;
                    }
                }
                mainForm.imageEditorDisplay1.mapa.bmp = ImageUtil.colorMatrixToBitmap(slika);
                mainForm.imageEditorDisplay1.FitImage();
                mainForm.imageEditorDisplay1.Refresh();
            }
        }

        private void btnSomFilter_Click(object sender, EventArgs e)
        {
            if (som == null)
                return;
            byte[, ,] slika = ImageUtil.bitmapToColorMatrix(orginalImage);

            // primeniti SOM
            DateTime d1 = DateTime.Now;
            int w = slika.GetLength(1);
            int h = slika.GetLength(0);
            byte[, ,] nslika = new byte[h, w, 3];

            for (int y = 0; y < h; y++)
            {
                for (int x = 0; x < w; x++)
                {
                    byte cbR = slika[y, x, 0];
                    byte cbG = slika[y, x, 1];
                    byte cbB = slika[y, x, 2];

                    double[] vektor = new double[3];
                    vektor[0] = cbR / 255.0;
                    vektor[1] = cbG / 255.0;
                    vektor[2] = cbB / 255.0;

                    Neuron nn = som.Pobednik(vektor);

                    nslika[y, x, 0] = (byte)(255 * nn.tezine[0]);
                    nslika[y, x, 1] = (byte)(255 * nn.tezine[1]);
                    nslika[y, x, 2] = (byte)(255 * nn.tezine[2]);
                }
            }
            DateTime d2 = DateTime.Now;
            Bitmap into = ImageUtil.colorMatrixToBitmap(nslika);
            mainForm.imageEditorDisplay1.mapa.bmp = into;
            mainForm.imageEditorDisplay1.FitImage();
            mainForm.imageEditorDisplay1.Refresh();
            TimeSpan ts1 = d2 - d1;
            imageEditorDisplay1.Refresh();
        }

        private void btnCopyToMain_Click(object sender, EventArgs e)
        {
            Bitmap bmp = (Bitmap)imageEditorDisplay1.mapa.bmp.Clone();
            mainForm.imageEditorDisplay1.mapa.bmp = bmp;
            mainForm.imageEditorDisplay1.FitImage();
            mainForm.imageEditorDisplay1.Refresh();
        }
    }
}
